voicemeeter\interface\callback/
data.rs

1//! Underlying data types for callbacks
2
3mod buffer_abstraction;
4
5pub use buffer_abstraction::{input, main, output, DeviceBuffer};
6
7use std::ptr::NonNull;
8
9use crate::types::{ChannelIndex, Device, VoicemeeterApplication};
10
11/// Audio information
12pub type AudioInfo = crate::bindings::VBVMR_T_AUDIOINFO;
13/// Audio buffers
14pub type AudioBuffer = crate::bindings::VBVMR_T_AUDIOBUFFER;
15
16impl AudioBuffer {
17    //#[tracing::instrument(level = "debug", skip(self))]
18    pub(crate) fn read_write_buffer(&self) -> (&[*mut f32], &[*mut f32]) {
19        let first_ptr_r = self.audiobuffer_r[0];
20        let first_ptr_w = self.audiobuffer_w[0];
21        for (idx, ptr) in self
22            .audiobuffer_r
23            .iter()
24            .enumerate()
25            .take(self.audiobuffer_nbi as usize)
26        {
27            debug_assert!(!ptr.is_null(), "ptr: {ptr:?} was null at idx: {idx}");
28        }
29        for (idx, ptr) in self
30            .audiobuffer_w
31            .iter()
32            .enumerate()
33            .take(self.audiobuffer_nbo as usize)
34        {
35            debug_assert!(!ptr.is_null(), "ptr: {ptr:?} was null at idx: {idx}");
36        }
37        //tracing::trace!("read_write_buffer: {:?}", self);
38
39        let k = (
40            &self.audiobuffer_r[..self.audiobuffer_nbi as usize],
41            &self.audiobuffer_w[..self.audiobuffer_nbo as usize],
42        );
43        // sanity check
44        debug_assert_eq!(first_ptr_r, k.0[0]);
45        debug_assert_eq!(first_ptr_w, k.1[0]);
46        k
47    }
48}
49
50#[repr(transparent)]
51/// Raw callback data
52pub struct RawCallbackData(NonNull<std::ffi::c_void>);
53
54impl std::fmt::Debug for RawCallbackData {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        write!(f, "{:p}", self.0)
57    }
58}
59// All of these tracing::instrument need to be skipped or we crash.
60impl RawCallbackData {
61    //#[tracing::instrument(level = "trace", skip_all,name = "RawCallbackData::from_ptr")]'
62    /// Create a new `RawCallbackData` from a raw pointer.
63    pub fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
64        RawCallbackData(NonNull::new(ptr).unwrap())
65    }
66    //#[tracing::instrument(level = "trace", skip_all,name = "RawCallbackData::as_audio_info")]
67    /// Get the audio information from the raw callback data.
68    ///
69    /// # Safety
70    ///
71    /// 1. This should not be called without ensuring that the pointer is in "scope" and that it is an [`AudioInfo`]
72    /// 2. All other conditions of [NonNull::as_mut] has to be met as well
73    pub unsafe fn as_audio_info<'a>(&self) -> &'a mut AudioInfo {
74        unsafe { self.0.cast().as_mut() }
75    }
76    //#[tracing::instrument(level = "trace", skip_all,name = "RawCallbackData::as_audio_buffer")]
77    /// Get the audio information from the raw callback data.
78    ///
79    /// # Safety
80    ///
81    /// 1. This should not be called without ensuring that the pointer is in "scope" and that it is an [`AudioBuffer`]
82    /// 2. All other conditions of [NonNull::as_mut] has to be met as well
83    pub unsafe fn as_audio_buffer<'a>(&self) -> &'a mut AudioBuffer {
84        unsafe { self.0.cast().as_mut() }
85    }
86}
87
88trait BufferDataExt<'a> {
89    /// Get the data inside the buffer as slices of pointers
90    fn data<'b>(&'b self) -> (&'a [*mut f32], &'a [*mut f32]);
91    /// Given a device, return a channel index
92    fn channel_index_write(&self, device: &Device) -> Option<ChannelIndex>;
93    fn channel_index_read(&self, device: &Device) -> Option<ChannelIndex>;
94    fn samples_per_frame(&self) -> usize;
95    /// Get the device write buffer for a device at idx.start..idx.start+N.
96    ///
97    /// This is unsafe because it can create mutable references arbitrarily.
98    #[inline]
99    unsafe fn device_write<'b, const N: usize>(
100        &'a self,
101        device: &Device,
102    ) -> DeviceBuffer<[&'b mut [f32]; N]> {
103        let idx = if let Some(idx) = self.channel_index_write(device) {
104            idx
105        } else {
106            return DeviceBuffer::None;
107        };
108        assert_eq!(N, idx.size);
109        let data = self.data().1;
110        // Each channel inside idx.start..(idx..start+idx.size) will be a *mut f32 that points to an array of `nbs` f32s.
111        let mut array = [(); N].map(|_| Default::default());
112        for i in 0..N {
113            let ptr = data[idx.start + i];
114            array[i] = unsafe { std::slice::from_raw_parts_mut(ptr, self.samples_per_frame()) };
115        }
116        DeviceBuffer::Buffer(array)
117    }
118    /// Get the device read buffer for a device at idx.start..idx.start+N.
119    ///
120    /// This is unsafe because it can create mutable references arbitrarily.
121    #[inline]
122    unsafe fn device_read<'b, const N: usize>(
123        &'a self,
124        device: &Device,
125    ) -> DeviceBuffer<[&'b [f32]; N]> {
126        let idx = if let Some(idx) = self.channel_index_read(device) {
127            idx
128        } else {
129            return DeviceBuffer::None;
130        };
131        assert_eq!(N, idx.size, "on device: {device:?}");
132        let data = self.data().0;
133        // Each channel inside idx.start..(idx..start+idx.size) will be a *mut f32 that points to an array of `nbs` f32s.
134        let mut array = [(); N].map(|_| Default::default());
135        for i in 0..N {
136            let ptr = data[idx.start + i];
137            array[i] = unsafe { std::slice::from_raw_parts(ptr, self.samples_per_frame()) };
138        }
139        DeviceBuffer::Buffer(array)
140    }
141}
142
143/// Buffer for main mode.
144///
145/// Retrieved via [`CallbackCommand::BufferMain`](crate::interface::callback::CallbackCommand::BufferMain)
146pub struct BufferMainData<'a> {
147    /// Read
148    pub read: main::ReadDevices<'a, 'a>,
149    /// Write
150    pub write: main::WriteDevices<'a, 'a>,
151}
152
153pub(crate) struct Main<'a> {
154    program: VoicemeeterApplication,
155    samples_per_frame: usize,
156    data: (&'a [*mut f32], &'a [*mut f32]),
157}
158
159impl<'a> BufferDataExt<'a> for Main<'a> {
160    #[inline]
161    fn data<'b>(&'b self) -> (&'a [*mut f32], &'a [*mut f32]) {
162        self.data
163    }
164
165    #[inline]
166    fn channel_index_read(&self, device: &Device) -> Option<ChannelIndex> {
167        device.main(&self.program).0
168    }
169
170    #[inline]
171    fn channel_index_write(&self, device: &Device) -> Option<ChannelIndex> {
172        device.main(&self.program).1
173    }
174
175    #[inline]
176    fn samples_per_frame(&self) -> usize {
177        self.samples_per_frame
178    }
179}
180
181//#[tracing::instrument(skip_all, name = "BufferMainData::new")]
182impl<'a> BufferMainData<'a> {
183    pub(crate) fn new<'b: 'a>(
184        program: VoicemeeterApplication,
185        data: &'b AudioBuffer,
186        samples_per_frame: usize,
187    ) -> Self {
188        let mut data = Main {
189            data: data.read_write_buffer(),
190            samples_per_frame,
191            program,
192        };
193        unsafe {
194            Self {
195                read: main::ReadDevices::new(&mut data),
196                write: main::WriteDevices::new(&mut data),
197            }
198        }
199    }
200
201    /// Convenience function to get the read and write buffers
202    ///
203    /// ```rust,no_run
204    /// # use voicemeeter::interface::callback::BufferMain; let data: BufferMain = unimplemented!();
205    /// let (read, mut write) = data.buffer.get_buffers();
206    /// ```
207    pub fn get_buffers(self) -> (main::ReadDevices<'a, 'a>, main::WriteDevices<'a, 'a>) {
208        (self.read, self.write)
209    }
210}
211
212/// Buffer for output mode.
213///
214/// Retrieved via [`CallbackCommand::BufferOut`](crate::interface::callback::CallbackCommand::BufferOut)
215pub struct BufferOutData<'a> {
216    /// Read
217    pub read: output::ReadDevices<'a, 'a>,
218    /// Write
219    pub write: output::WriteDevices<'a, 'a>,
220}
221pub(crate) struct Output<'a> {
222    program: VoicemeeterApplication,
223    samples_per_frame: usize,
224    data: (&'a [*mut f32], &'a [*mut f32]),
225}
226
227impl<'a> BufferDataExt<'a> for Output<'a> {
228    #[inline]
229    fn data<'b>(&'b self) -> (&'a [*mut f32], &'a [*mut f32]) {
230        self.data
231    }
232    #[inline]
233    fn channel_index_read(&self, device: &Device) -> Option<ChannelIndex> {
234        device.output(&self.program)
235    }
236
237    #[inline]
238    fn channel_index_write(&self, device: &Device) -> Option<ChannelIndex> {
239        device.output(&self.program)
240    }
241
242    #[inline]
243    fn samples_per_frame(&self) -> usize {
244        self.samples_per_frame
245    }
246}
247
248impl<'a> BufferOutData<'a> {
249    //#[tracing::instrument(skip_all, name = "BufferOutData::new")]
250    pub(crate) fn new(
251        program: VoicemeeterApplication,
252        data: &'a mut AudioBuffer,
253        samples_per_frame: usize,
254    ) -> Self {
255        let mut data = Output {
256            data: data.read_write_buffer(),
257            samples_per_frame,
258            program,
259        };
260        unsafe {
261            Self {
262                read: output::ReadDevices::new(&mut data),
263                write: output::WriteDevices::new(&mut data),
264            }
265        }
266    }
267
268    /// Convenience function to get the read and write buffers
269    ///
270    /// ```rust,no_run
271    /// # use voicemeeter::interface::callback::BufferOut; let data: BufferOut = unimplemented!();
272    /// let (read, mut write) = data.buffer.get_buffers();
273    /// ```
274    pub fn get_buffers(self) -> (output::ReadDevices<'a, 'a>, output::WriteDevices<'a, 'a>) {
275        (self.read, self.write)
276    }
277}
278
279/// Buffer for input mode.
280///
281/// Retrieved via [`CallbackCommand::BufferIn`](crate::interface::callback::CallbackCommand::BufferIn)
282pub struct BufferInData<'a> {
283    /// Read
284    pub read: input::ReadDevices<'a, 'a>,
285    /// Write
286    pub write: input::WriteDevices<'a, 'a>,
287}
288pub(crate) struct Input<'a> {
289    program: VoicemeeterApplication,
290    samples_per_frame: usize,
291    data: (&'a [*mut f32], &'a [*mut f32]),
292}
293
294impl<'a> BufferDataExt<'a> for Input<'a> {
295    #[inline]
296    fn data<'b>(&'b self) -> (&'a [*mut f32], &'a [*mut f32]) {
297        self.data
298    }
299    #[inline]
300    fn channel_index_read(&self, device: &Device) -> Option<ChannelIndex> {
301        device.input(&self.program)
302    }
303
304    #[inline]
305    fn channel_index_write(&self, device: &Device) -> Option<ChannelIndex> {
306        device.input(&self.program)
307    }
308
309    #[inline]
310    fn samples_per_frame(&self) -> usize {
311        self.samples_per_frame
312    }
313}
314
315impl<'a> BufferInData<'a> {
316    //#[tracing::instrument(skip_all, name = "BufferInData::new")]
317    pub(crate) fn new(
318        program: VoicemeeterApplication,
319        data: &'a mut AudioBuffer,
320        samples_per_frame: usize,
321    ) -> Self {
322        let mut data = Input {
323            data: data.read_write_buffer(),
324            samples_per_frame,
325            program,
326        };
327        unsafe {
328            Self {
329                read: input::ReadDevices::new(&mut data),
330                write: input::WriteDevices::new(&mut data),
331            }
332        }
333    }
334
335    /// Convenience function to get the read and write buffers
336    ///
337    /// ```rust,no_run
338    /// # use voicemeeter::interface::callback::BufferIn; let data: BufferIn = unimplemented!();
339    /// let (read, mut write) = data.buffer.get_buffers();
340    /// ```
341    pub fn get_buffers(self) -> (input::ReadDevices<'a, 'a>, input::WriteDevices<'a, 'a>) {
342        (self.read, self.write)
343    }
344}